﻿#include "Private.h"
#include "resource.h"
#include "BaseWindow.h"
#include "define.h"
#include "IMEBaseStructure.h"

namespace Global {
HINSTANCE dllInstanceHandle;

LONG dllRefCount = -1;

CRITICAL_SECTION CS;
HFONT defaultlFontHandle;				// Global font object we use everywhere

//---------------------------------------------------------------------
// MengYUWubi CLSID
//---------------------------------------------------------------------

//{754126c7-fa0d-442f-9763-c75055b606d8}
extern const CLSID WubiIMECLSID = { 
    0x754126c7, 
    0xfa0d, 
    0x442f, 
    { 0x97, 0x63, 0xc7, 0x50, 0x55, 0xb6, 0x06, 0xd8 } 
};

// {7c067c1f-64a1-4806-abb3-de2c1a9b6e28}
extern const GUID WubiIMEGuidProfile = { 
    0x7c067c1f,
    0x64a1,
    0x4806, 
    { 0xab, 0xb3, 0xde, 0x2c, 0x1a, 0x9b, 0x6e, 0x28 } 
};

// {f818bc6e-760d-4b81-b821-341d0e5e858a}
extern const GUID WubiIMEGuidImeModePreserveKey = {
    0xf818bc6e,  
    0x760d, 
    0x4b81, 
    { 0xb8, 0x21, 0x34, 0x1d, 0x0e, 0x5e, 0x85, 0x8a }
};

// {873cfa6b-f1b8-4f6c-85e0-6c50ce5a1ed8}
extern const GUID WubiIMEGuidCandUIElement = {
    0x873cfa6b,
    0xf1b8,
    0x4f6c,
    { 0x85, 0xe0, 0x6c, 0x50, 0xce, 0x5a, 0x1e, 0xd8 }
};


// {e700da61-d09a-428b-97f8-078775e15549}
extern const GUID WubiIMEGuidDoubleSingleBytePreserveKey = {
    0xe700da61, 
    0xd09a, 
    0x428b, 
    { 0x97, 0xf8, 0x07, 0x87, 0x75, 0xe1, 0x55, 0x49 } 
};

// {aadc6be7-1eb5-4697-b9ff-24a0abcd41e2}
extern const GUID WubiIMEGuidPunctuationPreserveKey = {
    0xaadc6be7, 
    0x1eb5, 
    0x4697,  
    { 0xb9, 0xff, 0x24, 0xa0, 0xab, 0xcd, 0x41, 0xe2 }
};

//---------------------------------------------------------------------
// Compartments
//---------------------------------------------------------------------
// {c655d206-4217-47e7-a8f7-ab9bae30d25b}
extern const GUID WubiIMEGuidCompartmentDoubleSingleByte = {
    0xc655d206, 
    0x4217, 
    0x47e7, 
    { 0xa8, 0xf7, 0xab, 0x9b, 0xae, 0x30, 0xd2, 0x5b } 
};

// {c227745d-8b4e-4b01-99b2-9d66ae403306}
extern const GUID WubiIMEGuidCompartmentPunctuation = {
    0xc227745d, 
    0x8b4e, 
    0x4b01, 
    { 0x99, 0xb2, 0x9d, 0x66, 0xae, 0x40, 0x33, 0x06 } 
};
//{1f4d3744-37c3-4ee8-8799-451675d79102}
extern const CLSID WubiIMEGuidCapsLockPreserveKey = {
    0x1f4d3744,
    0x37c3,
    0x4ee8,
    { 0x87, 0x99, 0x45, 0x16, 0x75, 0xd7, 0x91, 0x02 }
};

//{df1e6992-1383-4558-805f-feb020c61b9c}
extern const CLSID WubiIMEGuidOpenUIPreserveKey = {
    0xdf1e6992,
    0x1383,
    0x4558,
    { 0x80, 0x5f, 0xfe, 0xb0, 0x20, 0xc6, 0x1b, 0x9c }
};

//---------------------------------------------------------------------
// LanguageBars
//---------------------------------------------------------------------

// {9b436761-0db6-4184-ae94-5a888698821c}
extern const GUID WubiIMEGuidLangBarIMEMode = {
    0x9b436761,
    0x0db6,
    0x4184, 
    { 0xae, 0x94, 0x5a, 0x88, 0x86, 0x98, 0x82, 0x1c }
};

// {967a7664-7ca3-4dfc-95cc-345c550e49c2}
extern const GUID WubiIMEGuidLangBarDoubleSingleByte = {
    0x967a7664, 
    0x7ca3, 
    0x4dfc, 
    { 0x95, 0xcc, 0x34, 0x5c, 0x55, 0x0e, 0x49, 0xc2 } 
};

// {76c9d21b-8f9e-4b6c-a45f-08bef5bbb486}
extern const GUID WubiIMEGuidLangBarPunctuation = {
    0x76c9d21b,
    0x8f9e,  
    0x4b6c, 
    { 0xa4, 0x5f, 0x08, 0xbe, 0xf5, 0xbb, 0xb4, 0x86 }
};

// {8e5c3832-568b-4812-bbd3-b72af7922219}
extern const GUID WubiIMEGuidDisplayAttributeInput = {
    0x8e5c3832, 
    0x568b, 
    0x4812, 
    { 0xbb, 0xd3, 0xb7, 0x2a, 0xf7, 0x92, 0x22, 0x19 } 
};

// {3f6caba7-eccc-4ec4-9649-30efeb3d8861}
extern const GUID WubiIMEGuidDisplayAttributeConverted = {
    0x3f6caba7,
    0xeccc, 
    0x4ec4, 
    { 0x96, 0x49, 0x30, 0xef, 0xeb, 0x3d, 0x88, 0x61 } 
};




//---------------------------------------------------------------------
// Unicode byte order mark
//---------------------------------------------------------------------
extern const WCHAR UnicodeByteOrderMark = 0xFEFF;

//---------------------------------------------------------------------
// dictionary table delimiter
//---------------------------------------------------------------------
extern const WCHAR KeywordDelimiter = L'=';
extern const WCHAR StringDelimiter  = L'\"';

//---------------------------------------------------------------------
// defined item in setting file table [PreservedKey] section
//---------------------------------------------------------------------
extern const WCHAR ImeModeDescription[] = L"Chinese/English input (Shift)";
extern const int ImeModeOnIcoIndex = IME_MODE_ON_ICON_INDEX;
extern const int ImeModeOffIcoIndex = IME_MODE_OFF_ICON_INDEX;

extern const WCHAR DoubleSingleByteDescription[] = L"Double/Single byte (Shift+Space)";
// extern const int DoubleSingleByteOnIcoIndex = IME_DOUBLE_ON_INDEX;
// extern const int DoubleSingleByteOffIcoIndex = IME_DOUBLE_OFF_INDEX;

extern const WCHAR PunctuationDescription[] = L"Chinese/English punctuation (Ctrl+.)";
// extern const int PunctuationOnIcoIndex = IME_PUNCTUATION_ON_INDEX;
// extern const int PunctuationOffIcoIndex = IME_PUNCTUATION_OFF_INDEX;

//---------------------------------------------------------------------
// defined item in setting file table [LanguageBar] section
//---------------------------------------------------------------------
extern const WCHAR LangbarImeModeDescription[] = L"Conversion mode";
extern const WCHAR LangbarDoubleSingleByteDescription[] = L"Character width";
extern const WCHAR LangbarPunctuationDescription[] = L"Punctuation";

//---------------------------------------------------------------------
// windows class / titile / atom
//---------------------------------------------------------------------
extern const WCHAR CandidateClassName[] = L"MengYuWubi.CandidateWindow";
ATOM AtomCandidateWindow;

// extern const WCHAR ShadowClassName[] = L"MengYuWubi.ShadowWindow";
// ATOM AtomShadowWindow;

// extern const WCHAR ScrollBarClassName[] = L"MengYuWubi.ScrollBarWindow";
// ATOM AtomScrollBarWindow;

BOOL RegisterWindowClass()
{
    if (!CBaseWindow::_InitWindowClass(CandidateClassName, &AtomCandidateWindow))
    {
        return FALSE;
    }
    // if (!CBaseWindow::_InitWindowClass(ShadowClassName, &AtomShadowWindow))
    // {
    //     return FALSE;
    // }
    // if (!CBaseWindow::_InitWindowClass(ScrollBarClassName, &AtomScrollBarWindow))
    // {
    //     return FALSE;
    // }
    return TRUE;
}

//---------------------------------------------------------------------
// defined full width characters for Double/Single byte conversion
//---------------------------------------------------------------------
extern const WCHAR FullWidthCharTable[] = {
    //         !       "       #       $       %       &       '       (    )       *       +       ,       -       .       /
    0x3000, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07, 0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F,
    // 0       1       2       3       4       5       6       7       8       9       :       ;       <       =       >       ?
    0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17, 0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0xFF1F,
    // @       A       B       C       D       E       F       G       H       I       J       K       L       M       N       0
    0xFF20, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F,
    // P       Q       R       S       T       U       V       W       X       Y       Z       [       \       ]       ^       _
    0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F,
    // '       a       b       c       d       e       f       g       h       i       j       k       l       m       n       o       
    0xFF40, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
    // p       q       r       s       t       u       v       w       x       y       z       {       |       }       ~
    0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0xFF5B, 0xFF5C, 0xFF5D, 0xFF5E
};

//---------------------------------------------------------------------
// defined punctuation characters
//---------------------------------------------------------------------
// extern const struct _PUNCTUATION PunctuationTable[20] = {
//     {L'!',  (L"！")[0]},
//     {L'$',  (L"￥")[0]},
//     {L'&',  (L"＆")[0]},
//     {L'(',  (L"（")[0]},
//     {L')',  (L"）")[0]},
//     {L',',  (L"，")[0]},
//     {L'.',  (L"。")[0]},
//     {L':',  (L"：")[0]},
//     {L';',  (L"；")[0]},
//     {L'?',  (L"？")[0]},
//     {L'@',  (L"＠")[0]},
//     {L'\\', (L"、")[0]},
//     {L'^',  (L"＾")[0]},
//     {L'_',  (L"＿")[0]},
//     {L'[',  (L"【")[0]},
//     {L']',  (L"】")[0]},
//     {L'<',  (L"《")[0]},
//     {L'>',  (L"》")[0]},
//     {L'{',  (L"「")[0]},
//     {L'}',  (L"」")[0]},
// };

//+---------------------------------------------------------------------------
//
// CheckModifiers
//
//----------------------------------------------------------------------------

#define TF_MOD_ALLALT     (TF_MOD_RALT | TF_MOD_LALT | TF_MOD_ALT)
#define TF_MOD_ALLCONTROL (TF_MOD_RCONTROL | TF_MOD_LCONTROL | TF_MOD_CONTROL)
#define TF_MOD_ALLSHIFT   (TF_MOD_RSHIFT | TF_MOD_LSHIFT | TF_MOD_SHIFT)
#define TF_MOD_RLALT      (TF_MOD_RALT | TF_MOD_LALT)
#define TF_MOD_RLCONTROL  (TF_MOD_RCONTROL | TF_MOD_LCONTROL)
#define TF_MOD_RLSHIFT    (TF_MOD_RSHIFT | TF_MOD_LSHIFT)

#define CheckMod(m0, m1, mod)        \
    if (m1 & TF_MOD_ ## mod ##)      \
{ \
    if (!(m0 & TF_MOD_ ## mod ##)) \
{      \
    return FALSE;   \
}      \
} \
    else       \
{ \
    if ((m1 ^ m0) & TF_MOD_RL ## mod ##)    \
{      \
    return FALSE;   \
}      \
} \



BOOL CheckModifiers(UINT modCurrent, UINT mod)
{
    mod &= ~TF_MOD_ON_KEYUP;

    if (mod & TF_MOD_IGNORE_ALL_MODIFIER)
    {
        return TRUE;
    }

    if (modCurrent == mod)
    {
        return TRUE;
    }

    if (modCurrent && !mod)
    {
        return FALSE;
    }

    CheckMod(modCurrent, mod, ALT);
    CheckMod(modCurrent, mod, SHIFT);
    CheckMod(modCurrent, mod, CONTROL);

    return TRUE;
}

//+---------------------------------------------------------------------------
//
// UpdateModifiers
//
//    wParam - virtual-key code
//    lParam - [0-15]  Repeat count
//  [16-23] Scan code
//  [24]    Extended key
//  [25-28] Reserved
//  [29]    Context code
//  [30]    Previous key state
//  [31]    Transition state
//----------------------------------------------------------------------------

USHORT ModifiersValue = 0;
BOOL   IsShiftKeyDownOnly = FALSE;
BOOL   IsControlKeyDownOnly = FALSE;
BOOL   IsAltKeyDownOnly = FALSE;

BOOL UpdateModifiers(WPARAM wParam, LPARAM lParam)
{
    // high-order bit : key down
    // low-order bit  : toggled
    SHORT sksMenu = GetKeyState(VK_MENU);
    SHORT sksCtrl = GetKeyState(VK_CONTROL);
    SHORT sksShft = GetKeyState(VK_SHIFT);

    switch (wParam & 0xff)
    {
    case VK_MENU:
        // is VK_MENU down?
        if (sksMenu & 0x8000)
        {
            // is extended key?
            if (lParam & 0x01000000)
            {
                ModifiersValue |= (TF_MOD_RALT | TF_MOD_ALT);
            }
            else
            {
                ModifiersValue |= (TF_MOD_LALT | TF_MOD_ALT);
            }

            // is previous key state up?
            if (!(lParam & 0x40000000))
            {
                // is VK_CONTROL and VK_SHIFT up?
                if (!(sksCtrl & 0x8000) && !(sksShft & 0x8000))
                {
                    IsAltKeyDownOnly = TRUE;
                }
                else
                {
                    IsShiftKeyDownOnly = FALSE;
                    IsControlKeyDownOnly = FALSE;
                    IsAltKeyDownOnly = FALSE;
                }
            }
        }
        break;

    case VK_CONTROL:
        // is VK_CONTROL down?
        if (sksCtrl & 0x8000)    
        {
            // is extended key?
            if (lParam & 0x01000000)
            {
                ModifiersValue |= (TF_MOD_RCONTROL | TF_MOD_CONTROL);
            }
            else
            {
                ModifiersValue |= (TF_MOD_LCONTROL | TF_MOD_CONTROL);
            }

            // is previous key state up?
            if (!(lParam & 0x40000000))
            {
                // is VK_SHIFT and VK_MENU up?
                if (!(sksShft & 0x8000) && !(sksMenu & 0x8000))
                {
                    IsControlKeyDownOnly = TRUE;
                }
                else
                {
                    IsShiftKeyDownOnly = FALSE;
                    IsControlKeyDownOnly = FALSE;
                    IsAltKeyDownOnly = FALSE;
                }
            }
        }
        break;

    case VK_SHIFT:
        // is VK_SHIFT down?
        if (sksShft & 0x8000)    
        {
            // is scan code 0x36(right shift)?
            if (((lParam >> 16) & 0x00ff) == 0x36)
            {
                ModifiersValue |= (TF_MOD_RSHIFT | TF_MOD_SHIFT);
            }
            else
            {
                ModifiersValue |= (TF_MOD_LSHIFT | TF_MOD_SHIFT);
            }

            // is previous key state up?
            if (!(lParam & 0x40000000))
            {
                // is VK_MENU and VK_CONTROL up?
                if (!(sksMenu & 0x8000) && !(sksCtrl & 0x8000))
                {
                    IsShiftKeyDownOnly = TRUE;
                }
                else
                {
                    IsShiftKeyDownOnly = FALSE;
                    IsControlKeyDownOnly = FALSE;
                    IsAltKeyDownOnly = FALSE;
                }
            }
        }
        break;

    default:
        IsShiftKeyDownOnly = FALSE;
        IsControlKeyDownOnly = FALSE;
        IsAltKeyDownOnly = FALSE;
        break;
    }

    if (!(sksMenu & 0x8000))
    {
        ModifiersValue &= ~TF_MOD_ALLALT;
    }
    if (!(sksCtrl & 0x8000))
    {
        ModifiersValue &= ~TF_MOD_ALLCONTROL;
    }
    if (!(sksShft & 0x8000))
    {
        ModifiersValue &= ~TF_MOD_ALLSHIFT;
    }

    return TRUE;
}

//---------------------------------------------------------------------
// override CompareElements
//---------------------------------------------------------------------
BOOL CompareElements(LCID locale, const CStringRange* pElement1, const CStringRange* pElement2)
{
    return (CStringRange::Compare(locale, (CStringRange*)pElement1, (CStringRange*)pElement2) == CSTR_EQUAL) ? TRUE : FALSE;
}
}